package com.yanfan.zutai.config;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.yanfan.common.core.redis.RedisCache;
import com.yanfan.common.core.text.Convert;
import com.yanfan.common.utils.StringUtils;
import com.yanfan.common.utils.uuid.IdUtils;
import com.yanfan.iot.tdengine.config.TDengineDatabaseConfig;
import com.yanfan.iot.tdengine.dao.ZuTaiTDengineMapper;
import com.yanfan.mqtt.manager.MqttRemoteManager;
import com.yanfan.mqtt.model.PushMessageBo;
import com.yanfan.zutai.domain.*;
import com.yanfan.zutai.domain.vo.BDeviceEmqx;
import com.yanfan.zutai.domain.vo.BDeviceHeartData;
import com.yanfan.zutai.domain.vo.HeartData;
import com.yanfan.zutai.service.*;
import com.yanfan.zutai.util.DateUtilLocal;
import com.yanfan.zutai.util.Detect;
import com.yanfan.zutai.util.EntityUtil;
import lombok.extern.slf4j.Slf4j;
import org.nfunk.jep.JEP;
import org.nfunk.jep.Node;
import org.nfunk.jep.ParseException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
public class MqttDataServiceImpl {
    @Autowired
    private IBDeviceManagerService bDeviceManagerService;
    @Autowired
    private IBDeviceRealDataService bDeviceRealDataService;
    @Autowired
    private IBDeviceHistoryDataService bDeviceHistoryDataService;
    @Autowired
    private IBDeviceWarnConfigService bDeviceWarnConfigService;
    @Autowired
    private IBDevicePhoneService bDevicePhoneService;
    @Autowired
    private IBDeviceWarnService bDeviceWarnService;
    @Autowired
    private IBShortMessageService bShortMessageService;
    @Autowired
    private IBAppDeptService bAppDeptService;
    @Autowired
    private IBWeiXinService bWeiXinService;
    @Autowired
    private IBDeviceJsService bDeviceJsService;
    @Autowired
    private RedisCache redisCache;
    @Value("${spring.datasource.druid.tdengine-server.enabled}")
    private Boolean enabled;
    @Resource
    private MqttRemoteManager remoteManager;
    @Autowired(required = false)
    private ZuTaiTDengineMapper zuTaiTDengineMapper;
    @Autowired
    private TDengineDatabaseConfig tDengineDatabaseConfig;

    public void handleHeartbeatData(MsgQueue msgQueue) throws Exception {
        BDeviceHeartData heartData = new BDeviceHeartData();
        if (Detect.notEmpty(msgQueue.getImei())) {
            heartData.setImei(msgQueue.getImei());
        }
        BDeviceManager bDeviceManager = new BDeviceManager();
        // 自定义脚本js协议解析
        if (msgQueue.getTopic().indexOf("JAVASCRIPT/DATA") > -1) {
            bDeviceManager = bDeviceManagerService.selectBDeviceManagerByImei(msgQueue.getImei());
            if (bDeviceManager == null) {
                System.out.println("系统无此设备");
                return;
            }
            BDeviceJs bDeviceJs = bDeviceJsService.selectBDeviceJsByGuid(bDeviceManager.getScriptGuid());
            if (bDeviceJs == null) {
                System.out.println("系统无脚本解析");
                return;
            }
            ScriptEngineManager factory = new ScriptEngineManager();
            ScriptEngine engine = factory.getEngineByName("JavaScript");
            try {
                engine.eval(bDeviceJs.getScriptContent());
                Invocable inv = (Invocable) engine;
                Object reportToJson = inv.invokeFunction(bDeviceJs.getFunctionName(), msgQueue.getMessage());
                JSONArray objects = JSON.parseArray(reportToJson.toString());
                Map<String, Object> map = new HashMap<>();
                map.put("imei", heartData.getImei());
                map.put("data", objects);
                heartData = JSON.parseObject(JSON.toJSONString(map), BDeviceHeartData.class);
                System.out.println("自定义脚本解析：" + reportToJson);
            } catch (Exception e) {
                e.printStackTrace();
                System.out.println("脚步解析错误");
                return;
            }
        } else {
            heartData = JSON.parseObject(msgQueue.getMessage(), BDeviceHeartData.class);
            bDeviceManager = bDeviceManagerService.selectBDeviceManagerByImei(heartData.getImei());
            if (bDeviceManager == null) {
                System.out.println("系统无此设备");
                return;
            }
        }
        bDeviceManager.setReportTime(msgQueue.getReporteTime());
        bDeviceManager.setDeviceStatus(bDeviceManagerService.getDeviceWarnStatus(bDeviceManager.getDeviceMac()));
        bDeviceManagerService.updateBDeviceManager(bDeviceManager);
        Map<String, Object> mapReal = new HashMap<>();
        if (heartData.getData() != null) {
            for (int i = 0; i < heartData.getData().size(); i++) {
                HeartData data = heartData.getData().get(i);

                if (Detect.isEmpty(data.getM()) || Detect.isEmpty(data.getV())) {
                    System.out.println("无效的变量数据");
                    continue;
                }
                // 更新变量表
                BDeviceRealData bDeviceRealData = new BDeviceRealData();
                bDeviceRealData.setDeviceImei(heartData.getImei());
                bDeviceRealData.setParamField(data.getM());
                bDeviceRealData = bDeviceRealDataService.getRealData(bDeviceRealData);
                if (bDeviceRealData != null) {
                    Object paramValue = data.getV();
                    if (Detect.notEmpty(bDeviceRealData.getAcquisitionFormula())) {
                        String exp = bDeviceRealData.getAcquisitionFormula();
                        if (exp.indexOf("A") == -1) {
                            System.out.println("无效的公式");
                        } else {
                            exp = exp.replace(" ", "");
                            JEP jep = new JEP();
                            jep.addVariable("A", Convert.toDouble(paramValue));
                            Node parse = null;
                            try {
                                parse = jep.parse(exp);
                                paramValue = jep.evaluate(parse);
                                System.out.println("计算后的结果：" + paramValue);
                            } catch (ParseException e) {
                                System.out.println("公式有误，无法计算");
                            }
                        }
                    }
                    bDeviceRealData.setParamValue(Convert.toStr(paramValue));
                    bDeviceRealData.setReportTime(msgQueue.getReporteTime());
                    bDeviceRealDataService.updateBDeviceRealData(bDeviceRealData);
                    // 插入变量历史数据,改用taos时序数据库
                    BDeviceHistoryData historyData = new BDeviceHistoryData();
                    historyData.setParamField(bDeviceRealData.getParamField());
                    historyData.setParamName(bDeviceRealData.getParamName());
                    historyData.setParamValue(bDeviceRealData.getParamValue());
                    historyData.setParamUnit(bDeviceRealData.getParamUnit());
                    historyData.setReportTime(msgQueue.getReporteTime());
                    historyData.setDeviceImei(bDeviceManager.getDeviceMac());
                    historyData.setDeptIdStrs(bDeviceManager.getDeptIdStrs());
                    historyData.setDeviceName(bDeviceManager.getDeviceName());
                    try {
                        insertTaosHistory(historyData);
                    } catch (Exception e) {
                        e.printStackTrace();
                        System.out.println("插入时序数据库出错");
                    }
                    mapReal.put(data.getM(), data.getV());
                }
            }
            mapReal.put("t", DateUtilLocal.getSecondTimestampTwo(new Date()));
            String message = JSON.toJSONString(mapReal);
            String topic = "/IOT/WULIANYUN/REALDATA/" + bDeviceManager.getDeviceMac();
            // 通过内部mqtt客户端下发消息
            PushMessageBo zutaiBo = new PushMessageBo();
            zutaiBo.setQos(1);
            zutaiBo.setTopic(topic);
            zutaiBo.setMessage(message);
            remoteManager.pushCommon(zutaiBo);

            // 此缓存命令为success时说明设置设置指令成功
            if (msgQueue.getTopic().indexOf("SETUP/DATA") > -1) {
                redisCache.setCacheObject("Device-Reply-" + bDeviceManager.getDeviceMac(), "success");
            }
        }
    }

    public Boolean handleWarn(BDeviceRealData bDeviceRealData) throws Exception {
        // 判断报警间隔，满足条件触发报警，单位是秒
        Object alarmIntervalObj = redisCache.getCacheObject("Alarm-Interval-"
                + bDeviceRealData.getDeviceImei()
                + "-"
                + bDeviceRealData.getParamField());
        if (alarmIntervalObj != null) {
            return true;
        }
        if (bDeviceRealData.getComWaitingTime() != null) {
            redisCache.setCacheObject(
                    "Alarm-Interval-" + bDeviceRealData.getDeviceImei() + "-" + bDeviceRealData.getParamField(),
                    "success",
                    bDeviceRealData.getComWaitingTime(),
                    TimeUnit.SECONDS
            );
        } else {
            redisCache.setCacheObject(
                    "Alarm-Interval-" + bDeviceRealData.getDeviceImei() + "-" + bDeviceRealData.getParamField(),
                    "success",
                    60,
                    TimeUnit.SECONDS
            );
        }
        BDeviceManager bDeviceManager = bDeviceManagerService.selectBDeviceManagerByImei(bDeviceRealData.getDeviceImei());
        if (bDeviceManager == null) {
            System.out.println("系统无此设备");
            return false;
        }
        if (bDeviceManager.getId() == null) {
            System.out.println("系统无此设备");
            return false;
        }
        BDeviceWarnConfig bDeviceWarnConfig = new BDeviceWarnConfig();
        bDeviceWarnConfig.setRealDataGuid(bDeviceManager.getDeviceMac() + "-" + bDeviceRealData.getParamField());
        List<BDeviceWarnConfig> bDeviceWarnConfigs = bDeviceWarnConfigService.selectBDeviceWarnConfigList(bDeviceWarnConfig);
        Boolean isWarn = false;
        for (int i = 0; i < bDeviceWarnConfigs.size(); i++) {
            BDeviceWarnConfig warnConfig = bDeviceWarnConfigs.get(i);
            if (warnConfig.getStatus() == 0) {
                continue;
            }
            ////大于符合条件发出报警
            if (warnConfig.getWarnCondition() == 1 && Convert.toDouble(bDeviceRealData.getParamValue()) > warnConfig.getWarnValue()) {
                isWarn = true;
                sendMessage(bDeviceManager, warnConfig);
            }
            // 等于符合条件发出报警
            int compare = Convert.toDouble(bDeviceRealData.getParamValue()).compareTo(warnConfig.getWarnValue());
            if (warnConfig.getWarnCondition() == 2 && compare == 0) {
                isWarn = true;
                sendMessage(bDeviceManager, warnConfig);
            }
            // 小于符合条件发出报警
            if (warnConfig.getWarnCondition() == 3 && Convert.toDouble(bDeviceRealData.getParamValue()) < warnConfig.getWarnValue()) {
                isWarn = true;
                sendMessage(bDeviceManager, warnConfig);
            }
            // 大于等于符合条件发出报警
            if (warnConfig.getWarnCondition() == 4 && Convert.toDouble(bDeviceRealData.getParamValue()) >= warnConfig.getWarnValue()) {
                isWarn = true;
                sendMessage(bDeviceManager, warnConfig);
            }
            // 小于等于符合条件发出报警
            if (warnConfig.getWarnCondition() == 5 && Convert.toDouble(bDeviceRealData.getParamValue()) <= warnConfig.getWarnValue()) {
                isWarn = true;
                sendMessage(bDeviceManager, warnConfig);
            }
            // 不等于符合条件发出报警
            if (warnConfig.getWarnCondition() == 6 && compare != 0) {
                isWarn = true;
                sendMessage(bDeviceManager, warnConfig);
            }
        }
        if (isWarn) {
            if (bDeviceManager.getDeviceStatus() != 2) {
                bDeviceManager.setDeviceStatus(2);
                bDeviceManagerService.updateBDeviceManager(bDeviceManager);
            }
            redisCache.setCacheObject("DeviceWarn-" + bDeviceManager.getDeviceMac() + "-" + bDeviceRealData.getParamField(), 2);
        } else {
            redisCache.setCacheObject("DeviceWarn-" + bDeviceManager.getDeviceMac() + "-" + bDeviceRealData.getParamField(), 1);
        }
        return isWarn;
    }

    private void sendMessage(BDeviceManager bDeviceManager, BDeviceWarnConfig warnConfig) throws Exception {
        BDeviceRealData bDeviceRealData = new BDeviceRealData();
        BDeviceWarn bDeviceWarn = EntityUtil.mapping(bDeviceManager, BDeviceWarn.class);
        bDeviceWarn.setWarnTime(DateUtil.parse(DateUtil.now(), "yyyy-MM-dd HH:mm:ss"));
        bDeviceWarn.setWarnMessage(warnConfig.getWarnContent());
        bDeviceWarn.setAddress(bDeviceManager.getInstallationAddress());
        bDeviceWarn.setProcessState(0);
        bDeviceWarn.setWarnType("变量异常报警");
        if (Detect.notEmpty(warnConfig.getWarnType()) && warnConfig.getWarnType().indexOf("个推通知") > -1) {
            bDeviceWarnService.insertBDeviceWarn(bDeviceWarn);
            String message = JSON.toJSONString(bDeviceWarn);
            // 通过内部mqtt客户端下发消息
            PushMessageBo zutaiBo = new PushMessageBo();
            zutaiBo.setQos(1);
            zutaiBo.setTopic("/IOT/WULIANYUN/SENDWARNMESSAGE");
            zutaiBo.setMessage(message);
            remoteManager.pushCommon(zutaiBo);

            zutaiBo.setTopic("/IOT/WULIANYUN/ACCEPTZTMESSAGE/" + bDeviceManager.getDeviceMac());
            zutaiBo.setMessage(JSON.toJSONString(bDeviceWarn));
            remoteManager.pushCommon(zutaiBo);

            // APP个推
            String[] deptIds = bDeviceWarn.getDeptIdStrs().split(",");
            String warnMessage = bDeviceWarn.getDeviceName()
                    + "发出"
                    + bDeviceWarn.getWarnMessage()
                    + "，请您及时前往"
                    + bDeviceWarn.getAddress()
                    + "处理，谢谢！";
            for (int i = 0; i < deptIds.length; i++) {
                if (Detect.notEmpty(deptIds[i]) && !"0".equals(deptIds[i])) {
                    BAppDept bAppDept = new BAppDept();
                    bAppDept.setStatus(0);
                    bAppDept.setDeptId(Long.parseLong(deptIds[i]));
                    List<BAppDept> bAppDepts = bAppDeptService.selectBAppDeptList(bAppDept);
                    for (int j = 0; j < bAppDepts.size(); j++) {
                        BAppDept appDept = bAppDepts.get(j);
                        //   GTPushConfig.getInstance().sendMessage(appDept.getClientId(), "报警通知", warnMessage);
                    }
                }
            }
        }
        if (Detect.notEmpty(warnConfig.getWarnType()) && warnConfig.getWarnType().indexOf("短信通知") > -1) {
            BShortMessage bShortMessage = new BShortMessage();
            bShortMessage.setUserName(bDeviceManager.getCreateBy());
            List<BShortMessage> bShortMessages = bShortMessageService.selectBShortMessageList(bShortMessage);
            if (bShortMessages.size() > 0) {
                bShortMessage = bShortMessages.get(0);
            }
            if (bShortMessage.getId() != null && bShortMessage.getShortNotUseCount() > 0) {
                bDevicePhoneService.sendMessage(bDeviceWarn, bShortMessage);
            }
        }
        if (Detect.notEmpty(warnConfig.getWarnType()) && warnConfig.getWarnType().indexOf("公众号通知") > -1) {
            bDeviceWarn.setUpdateBy(bDeviceManager.getCreateBy());
            bWeiXinService.sendMsg(bDeviceWarn);
        }
        if (Detect.notEmpty(warnConfig.getWarnType()) && warnConfig.getWarnType().indexOf("变量读写") > -1) {
            String topic = "/IOT/WULIANYUN/ORDERSEND/" + bDeviceManager.getDeviceMac();
            bDeviceRealData.setParamName(warnConfig.getParamName());
            bDeviceRealData.setDeviceImei(bDeviceManager.getDeviceMac());
            List<BDeviceRealData> bDeviceRealDatas = bDeviceRealDataService.selectBDeviceRealDataList(bDeviceRealData);
            if (bDeviceRealDatas.size() > 0) {
                bDeviceRealData = bDeviceRealDatas.get(0);
                if (bDeviceRealData.getParamValue() == null || warnConfig.getParamValue() == null) {
                    return;
                }
                if (!bDeviceRealData.getParamValue().equals(warnConfig.getParamValue())) {
                    if (bDeviceRealData.getDataType() != null && bDeviceRealData.getDataType() == 4) {
                        bDeviceRealData.setParamValue(Convert.toFloat(warnConfig.getParamValue()).toString());
                    } else {
                        bDeviceRealData.setParamValue(Convert.toInt(warnConfig.getParamValue()).toString());
                    }
                    BDeviceDataTestVo mapping = EntityUtil.mapping(bDeviceRealData, BDeviceDataTestVo.class);
                    String message = JSON.toJSONString(mapping);
                    // 通过内部mqtt客户端下发消息
                    PushMessageBo zutaiBo = new PushMessageBo();
                    zutaiBo.setQos(1);
                    zutaiBo.setTopic(topic);
                    zutaiBo.setMessage(message);
                    remoteManager.pushCommon(zutaiBo);
                }
            }
        }
    }

    public void insertTaosHistory(BDeviceHistoryData bDeviceHistoryData) throws Exception {
        if (enabled) {
            if (StringUtils.isNotEmpty(bDeviceHistoryData.getParamValue()) && (NumberUtil.isNumber(bDeviceHistoryData.getParamValue()) || NumberUtil.isDouble(bDeviceHistoryData.getParamValue()))) {
                Snowflake snowflake = IdUtil.getSnowflake(6, 2);
                long id = snowflake.nextId();
                bDeviceHistoryData.setId(id);
                String sql = "INSERT INTO {} USING `" + tDengineDatabaseConfig.getDbName() + "`.`b_device_history_data` TAGS({}) VALUES " + "({}, '{}', '{}','{}','{}','{}','{}','{}');";
                String formatSql = StrUtil.format(sql,
                        tDengineDatabaseConfig.getDbName() +".d" + bDeviceHistoryData.getDeviceImei(),
                        bDeviceHistoryData.getId(),
                        IdUtils.nextTaosNsId(),
                        bDeviceHistoryData.getDeptIdStrs(),
                        bDeviceHistoryData.getDeviceImei(),
                        bDeviceHistoryData.getDeviceName(),
                        bDeviceHistoryData.getParamName(),
                        bDeviceHistoryData.getParamField(),
                        bDeviceHistoryData.getParamValue(),
                        bDeviceHistoryData.getParamUnit()
                );
                zuTaiTDengineMapper.updateBySql(formatSql);
            } else {
                // log.warn("数据异常，无法写入数据表");
            }
        } else {
            bDeviceHistoryDataService.insertBDeviceHistoryData(bDeviceHistoryData);
        }
    }

    public static boolean isInteger(String value) {
        if (value == null || value.isEmpty()) {
            return false;
        }
        // 检查字符串是否只包含数字和可能的负号
        if (!value.matches("-?\\d+")) {
            return false;
        }
        return true;
    }

    // 处理设备上下线通知
    public void handleDeviceStatus(MsgQueue msgQueue) throws Exception {
        BDeviceEmqx bDeviceEmqx = JSON.parseObject(msgQueue.getMessage(), BDeviceEmqx.class);
        BDeviceManager bDeviceManager = bDeviceManagerService.selectBDeviceManagerByImei(bDeviceEmqx.getClientid());
        if (bDeviceManager != null) {
            if (bDeviceEmqx.getConnected()) {
                bDeviceManager.setDeviceStatus(1);
                bDeviceManagerService.updateBDeviceManager(bDeviceManager);
            } else {
                bDeviceManager.setDeviceStatus(0);
                bDeviceManagerService.updateBDeviceManager(bDeviceManager);
            }
        }
    }
}
